﻿using System;
using System.ComponentModel;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Data;
using System.Collections;
using Microsoft.SharePoint.Publishing.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Collections.Generic;
using FTI.SP.LADM.EnhancedContentQueryWebPart.Exslt;
using System.Xml.Serialization;
using FTI.SP.LADM.EnhancedContentQueryWebPart.Wrappers;

namespace FTI.SP.LADM.EnhancedContentQueryWebPart
{
    [ToolboxData("<{0}:ContentQueryWithContextMenus runat=server></{0}:ContentQueryWithContextMenus>"), XmlRoot(Namespace = "FTI.SP.LADM.EnhancedContentQueryWebPart")]
    public class EnhancedContentQueryWebPart : ContentByQueryWebPart
    {
        #region Properties
        private bool showToolbar = false;
        public bool ShowToolbar
        {
            get
            {
                return showToolbar;
            }

            set
            {
                showToolbar = value;
            }
        }
        private bool showErrors = false;
        public bool ShowErrors
        {
            get
            {
                return showErrors;
            }

            set
            {
                showErrors = value;
            }
        }
        private bool showContextMenus = true;
        public bool ShowContextMenus
        {
            get
            {
                return showContextMenus;
            }

            set
            {
                showContextMenus = value;
            }
        }
        private bool forceCheckOut = true;
        public bool ForceCheckout
        {
            get
            {
                return forceCheckOut;
            }
            set
            {
                forceCheckOut = value;
            }
        }
        #endregion

        #region private variables
        private Dictionary<Guid, ListWrap> lists;
        private string errorText = "";
        private int customPageSize { get; set; }
        private string pagingParameterName { get; set; }
        public const int DefaultPageSize = 0;
        public const string DefaultPagingParameterName = "p";
        private int pageNumber;
        private int totalRecords;
        #endregion
        #region Data Columns Declarations
        DataColumn colSiteUrl;
        DataColumn colContextScriptID;
        DataColumn colContentQueryIndex;
        DataColumn colItemContentType;
        DataColumn colItemContentTypeID;
        DataColumn colItemApplicationName;
        DataColumn colItemOpenMethod;
        DataColumn colItemCheckedOut;
        DataColumn colItemCheckedOutUserID;
        DataColumn colItemIconUrl;
        DataColumn colItemExtension;
        DataColumn colItemFolder;
        DataColumn colItemUrl;

        DataColumn colDocType;
        DataColumn colCopySource;
        DataColumn colModerationStatus;
        DataColumn colDocEditCommand;
        DataColumn colDeclaredRecord;
        #endregion

        
        #region web part events

        protected override void CreateChildControls()
        {
            if (this.ShowContextMenus)
            {
                try
                {
                    
                    //force a call the ProcessItems function when ProcessData event is triggered.
                    //this.ProcessDataDelegate = new ProcessData(ProcessItems);

                    try
                    {
                        #region add list toolbar
                        if (this.ShowToolbar && !string.IsNullOrEmpty(this.ListName))
                        {

                            ViewToolBar toolbar = new ViewToolBar();
                            if (this.WebUrl != SPContext.Current.Web.Url)
                            {
                                //we are linking to a list on another site.
                                SPSite site = SPContext.Current.Site;
                                HttpRequest myReq = new HttpRequest("", SPContext.Current.Site.Url + this.WebUrl, "");
                                System.IO.StringWriter myWriter = new System.IO.StringWriter();
                                HttpResponse myRes = new HttpResponse(myWriter);
                                HttpContext myContext = new HttpContext(myReq, myRes);

                                using (SPWeb web = site.OpenWeb(this.WebUrl))
                                {
                                    SPList currentList = web.Lists[new Guid(this.ListGuid)];
                                    SPContext listContext = SPContext.GetContext(myContext, currentList.DefaultView.ID, currentList.ID, currentList.ParentWeb);
                                    toolbar.RenderContext = listContext;
                                }
                            }
                            else
                            {
                                //the list is on the current site
                                SPList currentList = SPContext.Current.Web.Lists[new Guid(this.ListGuid)];
                                SPContext listContext = SPContext.GetContext(this.Context, currentList.DefaultView.ID, currentList.ID, currentList.ParentWeb);
                                toolbar.RenderContext = listContext;
                            }
                            this.Controls.Add(toolbar);

                        }
                        #endregion
                    }
                    catch (Exception ex)
                    {
                        ReportError("Error creating the toolbar : " + ex.Message + "<br />" + ex.ToString());
                    }


                }
                catch (Exception ex)
                {
                    ReportError("CreateChildControls encountered an error : " + ex.Message + "<br />" + ex.ToString());
                }
            }
            base.CreateChildControls();
        }
        protected override void Render(System.Web.UI.HtmlTextWriter writer)
        {
            base.Render(writer);
            if (lists != null && this.ShowContextMenus)
            {
                foreach (KeyValuePair<Guid, ListWrap> list in lists)
                {
                    if (!string.IsNullOrEmpty(list.Value.ListTitle))
                    {
                        string listConextScript = list.Value.ContextScriptBlock;
                        writer.WriteLine(listConextScript);
                    }
                }
            }
            if (this.ShowErrors && !string.IsNullOrEmpty(errorText))
            {
                writer.WriteLine("<p>" + errorText + "</p>");
            }


        }
        public override ToolPart[] GetToolParts()
        {
            List<ToolPart> list = new List<ToolPart>(base.GetToolParts());
            list.Insert(1, new EnhancedContentQueryToolPart());
            return list.ToArray();
        }
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            
            if (this.CustomPageSize > 0)
            {
                this.pageNumber = 1;
                if (string.IsNullOrEmpty(this.PagingParameterName))
                {
                    this.PagingParameterName = "p";
                }
                string str = this.Page.Request.QueryString[this.PagingParameterName];
                if (!string.IsNullOrEmpty(str) && (!int.TryParse(str, out this.pageNumber) || (this.pageNumber < 1)))
                {
                    this.pageNumber = 1;
                }
                base.ProcessDataDelegate = (ContentByQueryWebPart.ProcessData)Delegate.Combine(base.ProcessDataDelegate, new ContentByQueryWebPart.ProcessData(this.processData));
            }
        }
        #endregion

        #region Data manipulation functions        
        /// <summary>
        /// Adds information to the data row (populates the custom data columns)
        /// </summary>
        /// <param name="row">The data row to add the information into</param>
        /// <param name="itemCounter">The unique id of the row in the web part</param>
        private void EditDataRow(DataRow row, int itemIndex)
        {
            try
            {
                SPSite site = SPControl.GetContextSite(this.Context);
                ListItemWrap currentItem = new ListItemWrap(row, site);
                row[colContentQueryIndex] = currentItem.ItemID;
                row[colSiteUrl] = currentItem.WebUrl;
                row[colItemIconUrl] = currentItem.ItemIconUrl;
                row[colItemExtension] = currentItem.ItemExtension;
                row[colItemApplicationName] = currentItem.ItemApplicationName;
                row[colItemOpenMethod] = currentItem.ItemOpenMethod;
                row[colItemCheckedOut] = currentItem.CheckedOut;
                if (currentItem.CheckedOutUserID != -1)
                    row[colItemCheckedOutUserID] = currentItem.CheckedOutUserID;
                else
                    row[colItemCheckedOutUserID] = "";
                row[colItemContentType] = currentItem.ItemContentType;
                row[colItemContentTypeID] = currentItem.ItemContentTypeID;
                row[colItemFolder] = currentItem.FolderUrl;
                row[colItemUrl] = currentItem.ItemUrl;

                row[colDocType] = currentItem.DocType;
                row[colCopySource] = currentItem.CopySource;
                row[colModerationStatus] = currentItem.ModerationStatus;
                row[colDocEditCommand] = currentItem.DocEditCommand;
                row[colDeclaredRecord] = currentItem.DeclaredRecord;
                ListWrap list = new ListWrap(currentItem);
                if (!lists.ContainsKey(list.ListID))
                {
                    int counter = lists.Count + 1;
                    list.ScriptContextID = "ctx" + this.ID + counter.ToString();
                    list.ContextID = counter;
                    list.ForceCheckout = this.ForceCheckout;
                    lists.Add(list.ListID, list);
                }
                else
                {
                    list = lists[list.ListID];
                }
                row[colContextScriptID] = list.ScriptContextID;
            }
            catch { }
        }
        private void AddCustomColumns(DataTable dt)
        {
            colSiteUrl = new DataColumn("SiteUrl");
            dt.Columns.Add(colSiteUrl);
            colContextScriptID = new DataColumn("ContextScriptID");
            dt.Columns.Add(colContextScriptID);
            colContentQueryIndex = new DataColumn("ItemIndex");
            dt.Columns.Add(colContentQueryIndex);
            colItemContentType = new DataColumn("ItemContentType");
            dt.Columns.Add(colItemContentType);
            colItemContentTypeID = new DataColumn("ItemContentTypeID");
            dt.Columns.Add(colItemContentTypeID);
            colItemApplicationName = new DataColumn("ItemApplicationName");
            dt.Columns.Add(colItemApplicationName);
            colItemOpenMethod = new DataColumn("ItemOpenMethod");
            dt.Columns.Add(colItemOpenMethod);
            colItemCheckedOut = new DataColumn("ItemCheckedOut");
            dt.Columns.Add(colItemCheckedOut);
            colItemCheckedOutUserID = new DataColumn("ItemCheckedOutUserID");
            dt.Columns.Add(colItemCheckedOutUserID);
            colItemIconUrl = new DataColumn("ItemIconUrl");
            dt.Columns.Add(colItemIconUrl);
            colItemExtension = new DataColumn("ItemExtension");
            dt.Columns.Add(colItemExtension);
            colItemFolder = new DataColumn("DocumentFolder");
            dt.Columns.Add(colItemFolder);
            colItemUrl = new DataColumn("ItemUrl");
            dt.Columns.Add(colItemUrl);

            colDocType = new DataColumn("DocType");
            dt.Columns.Add(colDocType);
            colCopySource = new DataColumn("CopySource");
            dt.Columns.Add(colCopySource);
            colModerationStatus = new DataColumn("ModerationStatus");
            dt.Columns.Add(colModerationStatus);
            colDocEditCommand = new DataColumn("DocEditCommand");
            dt.Columns.Add(colDocEditCommand);
            colDeclaredRecord = new DataColumn("_vti_ItemDeclaredRecord");
            dt.Columns.Add(colDeclaredRecord);
        }
        #endregion

        // Methods      

        protected override void ModifyXsltArgumentList(ArgumentClassWrapper argList)
        {
            if (this.CustomPageSize > 0)
            {
                argList.AddParameter("PageSize", "", this.CustomPageSize);
                argList.AddParameter("PagingParameterName", "", this.PagingParameterName);
                argList.AddParameter("TotalRecords", "", this.totalRecords);
                argList.AddParameter("PageNumber", "", this.pageNumber);
            }
            argList.AddParameter("WebPartTitle", string.Empty, this.Title);
            argList.AddParameter("WebPartDescription", string.Empty, this.Description);
            argList.AddParameter("WebPartTitleUrl", string.Empty, this.TitleUrl);
            argList.AddParameter("Locale", string.Empty, SPContext.Current.Web.Language);
            argList.AddParameter("GroupStyle", string.Empty, base.GroupStyle);
            argList.AddParameter("ItemStyle", string.Empty, base.ItemStyle);
            argList.AddExtensionObject("http://exslt.org/common", ExsltCommon.Instance);
            argList.AddExtensionObject("http://exslt.org/dates-and-times", ExsltDatesAndTimes.Instance);
            argList.AddExtensionObject("http://exslt.org/math", ExsltMath.Instance);
            argList.AddExtensionObject("http://exslt.org/regular-expressions", ExsltRegularExpressions.Instance);
            argList.AddExtensionObject("http://exslt.org/sets", ExsltSets.Instance);
            argList.AddExtensionObject("http://exslt.org/strings", ExsltStrings.Instance);
            argList.AddExtensionObject("http://schemas.imtechict.nl/SharePoint/WebParts/EnhancedContentQueryWebPart", EnhancedContentQueryWebPartFunctions.Instance);
            base.ModifyXsltArgumentList(argList);
        }
        protected DataTable processData(DataTable dt)
        {
            int num = (this.pageNumber - 1) * this.CustomPageSize;
            int count = num + this.CustomPageSize;
            this.totalRecords = dt.Rows.Count;
            DataTable table = dt.Clone();
            if (count >= dt.Rows.Count)
            {
                count = dt.Rows.Count;
            }
            if (num < dt.Rows.Count)
            {
                for (int i = num; i < count; i++)
                {
                    table.ImportRow(dt.Rows[i]);
                }
            }
            lists = new Dictionary<Guid, ListWrap>();
            int itemCounter = 0;

            //add the columns to the data that do not exist in the regular CQWP
            AddCustomColumns(table);

            //loop over the items in the results, and add the data for each item
            foreach (DataRow row in table.Rows)
            {
                itemCounter++;
                EditDataRow(row, itemCounter);
            }            
            return table;
        }
        protected DataTable ProcessItems(DataTable dt)
        {
            lists = new Dictionary<Guid, ListWrap>();
            int itemCounter = 0;

            //add the columns to the data that do not exist in the regular CQWP
            AddCustomColumns(dt);

            //loop over the items in the results, and add the data for each item
            foreach (DataRow row in dt.Rows)
            {
                itemCounter++;
                EditDataRow(row, itemCounter);
            }
            return dt;
        }
        // Properties
        [Category("Display"), Personalizable, WebDisplayName("Page Size"), WebBrowsable(false)]
        public int CustomPageSize
        {
            get { return this.customPageSize; }
            set { this.customPageSize = value; }
        }

        [WebBrowsable(false), Personalizable, Category("Display"), WebDisplayName("Paging Parameter")]
        public string PagingParameterName
        {
            get { return this.pagingParameterName; }
            set { this.pagingParameterName = value; }
        }
        #region debug functions
        private void ReportError(string message)
        {
            this.errorText += "<br />" + message;
        }
        #endregion
    }
}
